驗證(Authencation)跟授權(Authorize)常常讓人搞混(還是只有我)
舉例而言
有一家公司進出大門需要門禁卡
有沒有帶門禁卡與門禁卡是否有效這件事情是驗證(Authencation)
而有些地方,例如董事長辦公室,需要有主管階級的門禁卡才能進出
所以如果小蝦米如我帶著掛著菜逼八的有效門禁卡
依舊無法進出董事長辦公室
帶著有效的資訊,但因為沒有權限而無法做事,稱為授權(Authorize)
而今天主要要談的是
要怎麼拿到門禁卡以及驗證門禁卡是否有效(總不能拿著別家公司的卡來開門吧)的驗證(Authencation)
不是很知道怎麼稱呼發門禁卡(token or authencation ticket)的角色,姑且稱呼為Issuer
在訪問他人的大樓的時候,通常要先到櫃台換取門禁卡,櫃台本質上就是Issuer
而在web 應用程式中,要取得token 最常見的方式就是登入(login)
要換門禁卡的時候通常會需要押你的身分證件(Credential)
讓櫃台知道你是誰之後才給你門禁卡
同理,在登入的時候,會需要帶入帳號密碼,這也是一種(Credential)
有了Token 之後,雙方會協商要如何通過門禁,將token放在header/cookie 等等的方式
最後,當你要離開大樓的時候,會再跟門口的警衛或是櫃台跟他說我要離開了
他就會把token 收回
對應web 程式,這件事通常是「登出」 負責撤銷token的為Revoker
Claim 是當確認使用者身分之後,由issuer發派的
他是描述使用者資訊的物件
可以記錄使用者姓名,電話,email等基本資訊
又或者是使用者的權限(董事長,菜逼八)等等
這個物件最後會作為token的一部分(我的門禁卡上記錄著我是誰,我的權限是菜逼八)
Claim.cs
(節錄)
public class Claim
{
protected virtual byte[]? CustomSerializationData
{
get
{
return _userSerializationData;
}
}
public string Issuer
{
get { return _issuer; }
}
public string OriginalIssuer
{
get { return _originalIssuer; }
}
public IDictionary<string, string> Properties
{
get
{
if (_properties == null)
{
_properties = new Dictionary<string, string>();
}
return _properties;
}
}
public ClaimsIdentity? Subject
{
get { return _subject; }
}
public string Type
{
get { return _type; }
}
public string Value
{
get { return _value; }
}
public string ValueType
{
get { return _valueType; }
}
}
上面列的是幾個比較重要的屬性
Type
表示Claim所記錄的東西 通常會是ClaimTypes
msdn 裡的其中一項,也可以自訂字面翻譯是身分,裡面有個表現這個身分的稱謂Name
以及這個身分應該要如何驗證的AuthenticationType
還有是否被驗證過的IsAuthenticated
public interface IIdentity
{
// Access to the name string
string? Name { get; }
// Access to Authentication 'type' info
string? AuthenticationType { get; }
// Determine if this represents the unauthenticated identity
bool IsAuthenticated { get; }
}
這是一個很多咚咚的Class
繼承了IIdentity
source code
比較重要的是他有一個instanceClaims
的屬性
這個屬性存放了描述這個身分所有對應的Claim
private readonly List<Claim> _instanceClaims = new List<Claim>();
‵
同樣的Claim上所紀錄的Subject
則會assign給對應的ClaimIdentity
對驗證系統來說,接受認證的可能是一個實體的人
也有可能是一個application
對驗證系統來說
都會使用IPrincipal
來表示User的概念
public interface IPrincipal
{
// Retrieve the identity object
IIdentity? Identity { get; }
// Perform a check for a specific role
bool IsInRole(string role);
}
IsInRole()
方法可以決定這個身分是不是有權限操作要求的資源
ClaimIdentity
中包含了許多的Claim
而ClaimsPrincipal
中則包含了很多的 ClaimIdentity
source
一個使用者可以有多個身分,每個身分可能有不同的Claim
對於實作的IsInRole
方法
只要其中一個身分有Claim為該角色的話就會回傳true
舉例而言
小陳這個使用者(ClaimsPrincipal
)擁有董事長、公司職員的(ClaimIdentity
)
董事長這個ClaimIdentity
中有個Type為ClaimType.Role
且 Value
為董事長的 Claim
那麼呼叫IsInRole("董事長")
就會回傳true
另外,雖然小陳有很多身分
但是在使用IPrincipal
呼叫Identity
的時候
必須決定一個主要回傳的身分(如果我是小陳,我就會回傳董事長的身分)